-- AttribM
-- Create by panyl
-- 属性

module("AttribM", package.seeall);

local attribFormula = {};
local attribLimit   = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下attrib_formula_CSV信息表
    attribFormula = {};
    local attrib_formula_CSV = get_attrib_formula_CSV();
    for _, row in pairs(attrib_formula_CSV) do
        attribFormula[row["type"]] = attribFormula[row["type"]] or {};
        attribFormula[row["type"]][row["field"]] = row;
    end

    attrib_formula_CSV = {};

    -- 转换下attrib_limit_CSV信息表
    attribLimit = {};
    local attrib_limit_CSV = get_attrib_limit_CSV();
    for _, row in pairs(attrib_limit_CSV) do
        attribLimit[row["object_type"]] = attribLimit[row["object_type"]] or {};
        attribLimit[row["object_type"]][row["attrib"]] = row["value"];
    end

    attrib_limit_CSV = {};
end

function init()
    loadCsv();
end

-- 检索
function query(t, attrib)
    local m = attribFormula[t];
    if not m or not attrib then
        return m;
    end

    return m[attrib];
end

-- 检索属性限量
function queryAttribLimit(type, attrib)
    if attribLimit[type] and attribLimit[type][attrib] then
        return attribLimit[type][attrib];
    else
        return MAX_VALUE;
    end
end

-- 查询属性最大值
function maxAttrib(who, attrib)
    local objectType = who.type;
    local maxAttrib = queryAttribLimit(objectType, attrib);

    if type(maxAttrib) == "string" and
        string.startWith(maxAttrib, "formula_") then
        local prefix = "formula_";
        local formulaName = string.sub(maxAttrib, string.len(prefix) + 1);
        maxAttrib = FormulaM.invoke(formulaName, ME.user);
    end

    if type(maxAttrib) ~= "number" then
        maxAttrib = MAX_VALUE;
    end

    return maxAttrib;
end

-- 查询
function queryAttrib(who, attrib, args)
    Profiler.funcBegin("queryAttrib");
    local m = attribFormula[who.type];

    if not m or not m[attrib] then

        local ret = who.dbase:query(attrib, 0);
        Profiler.funcEnd("queryAttrib");
        return ret;
    end

    if args then
        -- 忽略debuff影响，需要单独计算
        local formula = m[attrib]["formula"];
        local ret = FormulaM.invoke(formula, who, args);
        Profiler.funcEnd("queryAttrib");
        return ret;
    end

    -- local value = who.dbase:query("attrib_cache", attrib);

    -- -- 数据还未脏，直接用上次计算好的
    -- if  not isDirty(who, attrib) and value then
    --     return value;
    -- end

    -- 重新公式计算
    local formula = m[attrib]["formula"];
    local value = FormulaM.invoke(formula, who, args);

    -- 缓存起来
    -- setDirty(who, attrib, false);
    -- who.dbase:set("attrib_cache", attrib, value);
    Profiler.funcEnd("queryAttrib");
    return value;
end

-- 标记全部属性污染字段
function setAllDirty(who, flag)
    -- 有点乱，暂时屏蔽掉
    do return end;

    if not flag then
        who.dbase:delete("dirty");
    else
        local m = attribFormula[who.type] or {};
        local data = who.dbase:query("dirty", {});

        for attrib, row in pairs(m) do
            if row["dirty"] == 1 then
                data[attrib] = true;
            end
        end

        who.dbase:set("dirty", data);
    end
end

-- 标记数据被污染了
function setDirty(who, attrib, flag)
    -- 暂时屏蔽掉
    do return; end

    local m = attribFormula[who.type];
    if not m or m[attrib] and m[attrib]["dirty"] ~= 1 then
        return;
    end

    local m = who.dbase:query("dirty", {});

    if not flag then
        m[attrib] = nil;
    else
        m[attrib] = flag;
    end

    who.dbase:set("dirty", m);
end

-- 数据是否已经脏了
function isDirty(who, attrib)
    -- 除了玩家，其他类型的对象都需要重新计算
    if who.type ~= OBJECT_TYPE_USER then
        return true;
    end

    local m = attribFormula[who.type];
    if m[attrib]["dirty"] ~= 1 then
        return true;
    end

    local m = who.dbase:query("dirty", {});

    return m[attrib];
end

-- 安装触发器
function installTrigger(who)

    -- 暂时屏蔽掉
    do return; end

    local m = attribFormula[who.type];
    if not m then
        return;
    end

    -- 属性变动时，所有属性都脏了
    who.dbase:registerCb("AttribM", { "prop", }, function()
        setAllDirty(who, true)
    end);

    for attrib, row in pairs(m) do
        if row["dirty"] == 1 then
            who.dbase:registerCb("AttribM", { attrib, }, function()
                setDirty(who, attrib, true);
            end);
        end
    end
end

